import logging
import urllib
from datetime import datetime
from django.db import models
from django.contrib.sites.models import Site
from settings import AQL_USERNAME, AQL_PASSWORD, AQL_CALLBACK
from signals import aql_sms_sent

# the HTTP->SMS gateways to use
gw_addrs = ('http://gw1.aql.com/sms/sms_gw.php',
            'http://gw2.aql.com/sms/sms_gw.php')

# status codes
STAT_SUCCESS = 0
STAT_PARTIAL = 1
STAT_AUTHERR = 2
STAT_NUMERR = 3
STAT_TIMEERR = 4
STAT_CREDIT = 5
STAT_UNDEF = 9
# used internally
SERVER_ERR = 99

STATUS_CODES = (
    (STAT_SUCCESS, 'SMS successfully queued'),
    (STAT_PARTIAL, 'SMS queued partially'),
    (STAT_AUTHERR, 'Authentication error'),
    (STAT_NUMERR, 'Destination number(s) error'),
    (STAT_TIMEERR, 'Send time error'),
    (STAT_CREDIT, 'Insufficient credit or invalid number of msg/destination'),
    (STAT_UNDEF, 'Undefined error'),
    )

# delivery codes
SMS_DELIVERED = 1
SMS_REJECTED = 2
SMS_BUFFERED = 4
SMSC_ACCEPTED = 8
SMSC_REJECTED = 16

DLR_CODES = (
    (SMS_DELIVERED, 'Delivered to Handset'),
    (SMS_REJECTED, 'Rejected from Handset'),
    (SMS_BUFFERED, 'Buffered in transit (phone probably off / out of reception)'),
    (SMSC_ACCEPTED, 'Accepted by SMSC'),
    (SMSC_REJECTED, 'Rejected by SMSC'),
    )

class TextMessage(models.Model):
    """"""
    tel_num = models.PositiveIntegerField()
    message = models.TextField()
    date_created = models.DateTimeField(auto_now_add=True)
    date_sent = models.DateTimeField(null=True, blank=True)
    date_callback = models.DateTimeField(null=True, blank=True)
    status_code = models.PositiveSmallIntegerField(null=True, blank=True, choices=STATUS_CODES)
    delivery_code = models.PositiveSmallIntegerField(null=True, blank=True, choices=DLR_CODES)
    credits_used = models.PositiveSmallIntegerField(default=0)
    
    def __unicode__(self):
        return self.message
    
    @models.permalink
    def get_absolute_url(self):
        return ('process_aql_callback', (), {
                'sms_id': self.id,
                })
    
    def send(self, callback=AQL_CALLBACK, **kwargs):
        """Send the TextMessage using the AQL HTTP to SMS gateway(s)
        
        **kwargs are optional parameters to pass to the gw:
        
            originator
            max_concat (limit concatenation)
            sendtime (in the format of "yyyy-mm-dd hh:mm:ss")
            replace_sms (1(one) or 0(zero))
            flash (1(one) or 0(zero))"""
        gw_rslt = None
        self.status_code = SERVER_ERR
        
        # try to send the message then make some changes to the object
        # before saving it later
        for gw_addr in gw_addrs:
            try:
                params = {}
                if callback:
                    params.update({'dlr_url': 'http://%s%s?reportcode=%%code&destinationnumber=%%dest' % (Site.objects.get_current().domain, self.get_absolute_url())})
                params.update(kwargs)
                req_vars = {'username': AQL_USERNAME,
                            'password': AQL_PASSWORD,
                            'destination': self.tel_num,
                            'message': self.message}
                params.update(req_vars)
                param_string = urllib.urlencode(params)
                aql_rslt = urllib.urlopen('%s?%s' % (gw_addr, param_string))
                rslt = aql_rslt.readline().split(':')
                status_code = rslt[0]
                credits_used = rslt[1].split(' ')[0]
                self.credits_used = int(credits_used)
                self.status_code = int(status_code)
                self.date_sent = datetime.now()
                # if we've got this far the message has been processed by AQL
                break
            except IOError:
                continue
        
        # the object has hopefully been modified by data obtained by a GET
        self.save()
        # a little more verbose logging of a few important errors
        if self.status_code == SERVER_ERR:
            logging.error('Could not communicate with any SMS gateways')
        elif self.status_code == STAT_AUTHERR:
            logging.error('Could not authenticate with supplied username/password')
        elif self.status_code == STAT_CREDIT:
            logging.error('No credit')
        
        #probably a better way to translate this but this ok for now
        stat = [status[1] for status in STATUS_CODES if status[0] == self.status_code][0]
        aql_sms_sent.send(sender=self.__class__, instance=self, status_string=stat)
    
def check_credit():
    """"""
    pass
